/*--------------------------------------------------------------------------
Modified from GNU Group's SDCC
Only for study purpose
---------------------------------------------------------------------------*/

#include "common.h"
#include "value.h"
#include "parser.h"

/*-----------------------------------------------------------------*/
/* newValue - allocates and returns a new value        */
/*-----------------------------------------------------------------*/
value * newValue (void)
{
	value *val;
	val = Safe_alloc (sizeof (value));
	return val;
}


/*------------------------------------------------------------------*/
/* valFromType - creates a value from type given                    */
/*------------------------------------------------------------------*/
value *
valFromType (sym_link * type)
{
  value *val = newValue ();
  val->type = copyLinkChain (type);
  val->etype = getSpec (val->type);
  return val;
}

/*------------------------------------------------------------------*/
/* floatFromVal - value to double float conversion                  */
/*------------------------------------------------------------------*/
double
floatFromVal (value * val)
{
  if (!val)
    return 0;

  if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
    {
      //werror (E_CONST_EXPECTED, val->name);
		printf("Error: E_CONST_EXPECTED");
      return 0;
    }

  /* if it is not a specifier then we can assume that */
  /* it will be an unsigned long                      */
  if (!IS_SPEC (val->type))
    return SPEC_CVAL (val->etype).v_ulong;

  if (SPEC_LONG (val->etype))
    {
      if (SPEC_USIGN (val->etype))
        return SPEC_CVAL (val->etype).v_ulong;
      else
        return SPEC_CVAL (val->etype).v_long;
    }

  if (SPEC_NOUN (val->etype) == V_INT)
    {
      if (SPEC_USIGN (val->etype))
        return SPEC_CVAL (val->etype).v_uint;
      else
        return SPEC_CVAL (val->etype).v_int;
    }

  if (SPEC_NOUN (val->etype) == V_CHAR)
    {
      if (SPEC_USIGN (val->etype))
        return (unsigned char) SPEC_CVAL (val->etype).v_uint;
      else
        return (signed char) SPEC_CVAL (val->etype).v_int;
    }

  if (SPEC_NOUN (val->etype) == V_VOID)
    return SPEC_CVAL (val->etype).v_ulong;

  /* we are lost ! */
  //werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "floatFromVal: unknown value");
  printf("Error: floatFromVal: unknown value");
  return 0;
}

/*-----------------------------------------------------------------*/
/* constVal - converts an INTEGER constant into a cheapest value   */
/*-----------------------------------------------------------------*/
value *constVal (const char *s)
{
  value *val;
  char *p;
  double dval;
  bool is_integral = 0;

  val = newValue ();            /* alloc space for value   */

  val->type = val->etype = newLink (SPECIFIER); /* create the specifier */
  SPEC_SCLS (val->type) = S_LITERAL;

  /* let's start with a signed char */
  SPEC_NOUN (val->type) = V_CHAR;
  SPEC_USIGN (val->type) = 0;

  errno = 0;
  if (s[0] == '0')
    {
      if (s[1] == 'b' || s[1] == 'B')
        dval = strtoul (s + 2, &p, 2);
      else
        dval = strtoul (s, &p, 0);
      is_integral = 1;
    }
  else
    dval = strtod (s, &p);

  if (errno)
    {
      dval = 4294967295.0;
      //werror (W_INVALID_INT_CONST, s, dval);
	  printf("Error: %s: %f", s, dval);
    }

  /* Setup the flags first */
  /* set the unsigned flag if 'uU' is found */
  if (strchr (p, 'u') || strchr (p, 'U'))
    {
      SPEC_USIGN (val->type) = 1;
    }

  /* set the b_long flag if 'lL' is found */
  if (strchr (p, 'l') || strchr (p, 'L'))
    {
      SPEC_NOUN (val->type) = V_INT;
      SPEC_LONG (val->type) = 1;
    }
  else
    {
      if (dval < 0)
        { /* "-28u" will still be signed and negative */
          if (dval < -128)
            { /* check if we have to promote to int */
              SPEC_NOUN (val->type) = V_INT;
            }
          if (dval < -32768)
            { /* check if we have to promote to long int */
              SPEC_LONG (val->type) = 1;
            }
        }
      else
        { /* >=0 */
          if (dval > 0xff ||  /* check if we have to promote to int */
            SPEC_USIGN (val->type))
            { /* if it's unsigned, we can't use unsigned
                 char. After an integral promotion it will
                 be a signed int; this certainly isn't what
                 the programer wants */
              SPEC_NOUN (val->type) = V_INT;
            }
          else
            { /* store char's always as unsigned; this helps other optimizations */
              SPEC_USIGN (val->type) = 1;
            }
          if (dval > 0xffff && SPEC_USIGN (val->type))
            { /* check if we have to promote to long */
              SPEC_LONG (val->type) = 1;
            }
          else if (dval > 0x7fff && !SPEC_USIGN (val->type))
            { /* check if we have to promote to long int */
              if (is_integral && /* integral (hex, octal and binary)  constants may be stored in unsigned type */
                dval <= 0xffff)
                {
                  SPEC_USIGN (val->type) = 1;
                }
              else
                {
                  SPEC_LONG (val->type) = 1;
                  if (dval > 0x7fffffff)
                    {
                      SPEC_USIGN (val->type) = 1;
                    }
                }
            }
        }
    }

  /* check for out of range */
  if (dval < -2147483648.0)
    {
      dval = -2147483648.0;
      //werror (W_INVALID_INT_CONST, s, dval);
	  printf("Error: %s: %f", s, dval);
    }
  if (dval > 2147483647.0 && !SPEC_USIGN (val->type))
    {
      dval = 2147483647.0;
      //werror (W_INVALID_INT_CONST, s, dval);
	  printf("Error: %s: %f", s, dval);
    }
  if (dval > 4294967295.0)
    {
      dval = 4294967295.0;
      //werror (W_INVALID_INT_CONST, s, dval);
	  printf("Error: %s: %f", s, dval);
    }

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        {
          SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) double2ul (dval);
        }
      else
        {
          SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) double2ul (dval);
        }
    }
  else
    {
      if (SPEC_USIGN (val->type))
        {
          SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) double2ul (dval);
        }
      else
        {
          SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) double2ul (dval);
        }
    }

  return val;
}

/*------------------------------------------------------------------*/
/* ulFromVal - value to unsigned long conversion                    */
/*------------------------------------------------------------------*/
unsigned long
ulFromVal (value * val)
{
  if (!val)
    return 0;

  if (val->etype && SPEC_SCLS (val->etype) != S_LITERAL)
    {
      //werror (E_CONST_EXPECTED, val->name);
		printf("Error: E_CONST_EXPECTED");
      return 0;
    }

  /* if it is not a specifier then we can assume that */
  /* it will be an unsigned long                      */
  if (!IS_SPEC (val->type))
    return SPEC_CVAL (val->etype).v_ulong;

  if (SPEC_LONG (val->etype))
    {
      if (SPEC_USIGN (val->etype))
        return SPEC_CVAL (val->etype).v_ulong;
      else
        return SPEC_CVAL (val->etype).v_long;
    }

  if (SPEC_NOUN (val->etype) == V_INT)
    {
      if (SPEC_USIGN (val->etype))
        return SPEC_CVAL (val->etype).v_uint;
      else
        return SPEC_CVAL (val->etype).v_int;
    }

  if (SPEC_NOUN (val->etype) == V_CHAR)
    {
      if (SPEC_USIGN (val->etype))
        return (unsigned char) SPEC_CVAL (val->etype).v_uint;
      else
        return (signed char) SPEC_CVAL (val->etype).v_int;
    }

  if (SPEC_NOUN (val->etype) == V_VOID)
    return SPEC_CVAL (val->etype).v_ulong;

  /* we are lost ! */
  //werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "ulFromVal: unknown value");
  printf("Error: ulFromVal: unknown value");
  return 0;
}

/*-----------------------------------------------------------------*/
/* constVal - converts an CHAR constant into a cheapest value	   */
/*-----------------------------------------------------------------*/
value *constCharVal (unsigned char v)
{
  value *val = newValue ();            /* alloc space for value   */

  val->type = val->etype = newLink (SPECIFIER); /* create the specifier */
  SPEC_SCLS (val->type) = S_LITERAL;

  SPEC_NOUN (val->type) = V_CHAR;
  SPEC_CVAL (val->type).v_int = (signed char) v;

  return val;
}

/*------------------------------------------------------------------*/
/* charVal - converts a character constant to a value               */
/*------------------------------------------------------------------*/
value * charVal (const char *s)
{
  /* get rid of quotation */
  /* if \ then special processing */
  if (*++s == '\\')
    {
      switch (*++s)             /* go beyond the backslash  */
        {
        case 'n':
          return constCharVal ('\n');
        case 't':
          return constCharVal ('\t');
        case 'v':
          return constCharVal ('\v');
        case 'b':
          return constCharVal ('\b');
        case 'r':
          return constCharVal ('\r');
        case 'f':
          return constCharVal ('\f');
        case 'a':
          return constCharVal ('\a');
        case '\\':
          return constCharVal ('\\');
        case '\?':
          return constCharVal ('\?');
        case '\'':
          return constCharVal ('\'');
        case '\"':
          return constCharVal ('\"');

        case '0' :
        case '1' :
        case '2' :
        case '3' :
        case '4' :
        case '5' :
        case '6' :
        case '7' :
          return constCharVal (octalEscape (&s));

        case 'x':
          return constCharVal (hexEscape (&s));

        default:
           return constCharVal (*s);
        }
    }
  else                          /* not a backslash */
    return constCharVal (*s);
}


/*-----------------------------------------------------------------*/
/* valueFromLit - creates a value from a literal                   */
/*-----------------------------------------------------------------*/
value *
valueFromLit (long lit)
{
  char buffer[50];
 
  sprintf(buffer, "%d", (TYPE_TARGET_LONG) lit);
  return constVal (buffer);
}


/*--------------------------------------------------------------------*/
/* cheapestVal - try to reduce 'signed int' to 'char'                 */
/*--------------------------------------------------------------------*/
static value *
cheapestVal (value *val)
{
  /* only int can be reduced */
  if (!IS_INT(val->type))
    return val;

  /* long must not be changed */
  if (SPEC_LONG(val->type))
    return val;

  /* unsigned must not be changed */
  if (SPEC_USIGN(val->type))
    return val;

  /* the only possible reduction is from signed int to (un)signed char,
     because it's automatically promoted back to signed int.

     a reduction from unsigned int to unsigned char is a bug,
     because an _unsigned_ char is promoted to _signed_ int! */
  if (SPEC_CVAL(val->type).v_int < -128 ||
      SPEC_CVAL(val->type).v_int >  255)
    {
      /* not in the range of (un)signed char */
      return val;
    }

  SPEC_NOUN(val->type) = V_CHAR;

  /* 'unsigned char' promotes to 'signed int', so that we can
     reduce it the other way */
  if (SPEC_CVAL(val->type).v_int >= 0)
    {
      SPEC_USIGN(val->type) = 1;
    }
  return (val);
}


/*------------------------------------------------------------------*/
/* valueComplement - complements a constant                         */
/*------------------------------------------------------------------*/
value *
valComplement (value * val)
{
  /* depending on type */
  if (SPEC_LONG (val->etype))
    {
      if (SPEC_USIGN (val->etype))
        SPEC_CVAL (val->etype).v_ulong = ~SPEC_CVAL (val->etype).v_ulong;
      else
        SPEC_CVAL (val->etype).v_long = ~SPEC_CVAL (val->etype).v_long;
    }
  else
    {
      if (SPEC_USIGN (val->etype))
        SPEC_CVAL (val->etype).v_uint = ~SPEC_CVAL (val->etype).v_uint;
      else
        SPEC_CVAL (val->etype).v_int = ~SPEC_CVAL (val->etype).v_int;

      if (SPEC_NOUN(val->etype) == V_CHAR)
        {
          /* promote to 'signed int', cheapestVal() might reduce it again */
          SPEC_USIGN(val->etype) = 0;
          SPEC_NOUN(val->etype) = V_INT;
        }
      return cheapestVal (val);
    }
  return val;
}

/*------------------------------------------------------------------*/
/* valueNot - complements a constant                                */
/*------------------------------------------------------------------*/
value *
valNot (value * val)
{
  /* depending on type */
  if (SPEC_LONG (val->etype))
    {
      if (SPEC_USIGN (val->etype))
        SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_ulong;
      else
        SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_long;
    }
  else
    {
      if (SPEC_USIGN (val->etype))
        SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_uint;
      else
        SPEC_CVAL (val->etype).v_int = !SPEC_CVAL (val->etype).v_int;

    }
  SPEC_USIGN(val->etype) = 1;
  SPEC_LONG (val->etype) = 0;
  SPEC_NOUN(val->etype) = V_CHAR;
  return val;
}

/*------------------------------------------------------------------*/
/* computeTypeOr - computes the resultant type from two types       */
/*------------------------------------------------------------------*/
static sym_link *
computeTypeOr (sym_link * etype1, sym_link * etype2, sym_link * reType)
{
  /* sanity check */
  assert (IS_CHAR (etype1) && IS_CHAR (etype2));

  if (SPEC_USIGN (etype1) == SPEC_USIGN (etype2))
    {
      SPEC_USIGN (reType) = SPEC_USIGN (etype1);
      return reType;
    }

  if (SPEC_USIGN (etype1))
    {
      if (   IS_LITERAL (etype2)
          && floatFromVal (valFromType (etype2)) >= 0)
        SPEC_USIGN (reType) = 1;
      else
        {
          /* promote to int */
          SPEC_USIGN (reType) = 0;
          SPEC_NOUN (reType) = V_INT;
        }
    }
  else /* etype1 signed */
    {
      if (   IS_LITERAL (etype2)
          && floatFromVal (valFromType (etype2)) <= 127)
        SPEC_USIGN (reType) = 0;
      else
        {
          /* promote to int */
          SPEC_USIGN (reType) = 0;
          SPEC_NOUN (reType) = V_INT;
        }
    }

  if (SPEC_USIGN (etype2))
    {
      if (   IS_LITERAL (etype1)
          && floatFromVal (valFromType (etype1)) >= 0)
        SPEC_USIGN (reType) = 1;
      else
        {
          /* promote to int */
          SPEC_USIGN (reType) = 0;
          SPEC_NOUN (reType) = V_INT;
        }
    }
  else /* etype2 signed */
    {
      if (   IS_LITERAL (etype1)
          && floatFromVal (valFromType (etype1)) <= 127)
        SPEC_USIGN (reType) = 0;
      else
        {
          /* promote to int */
          SPEC_USIGN (reType) = 0;
          SPEC_NOUN (reType) = V_INT;
        }
    }
  return reType;
}


/*------------------------------------------------------------------*/
/* computeType - computes the resultant type from two types         */
/*------------------------------------------------------------------*/
sym_link *
computeType (sym_link * type1, sym_link * type2,
             int op)
{
  sym_link *rType;
  sym_link *reType;
  sym_link *etype1 = getSpec (type1);
  sym_link *etype2;

  etype2 = type2 ? getSpec (type2) : type1;

  /* if one of them is a pointer or array then that
     prevails */
  if (IS_PTR (type1) || IS_ARRAY (type1))
    rType = copyLinkChain (type1);
  else if (IS_PTR (type2) || IS_ARRAY (type2))
    rType = copyLinkChain (type2);
  else if (getSize (type1) > getSize (type2))
    rType = copyLinkChain (type1);
  else
    rType = copyLinkChain (type2);

  reType = getSpec (rType);

  /* avoid conflicting types */
  reType->select.s.b_signed = 0;

  /* if result is a literal then make not so */
  if (IS_LITERAL (reType))
    SPEC_SCLS (reType) = S_REGISTER;

  if (   (SPEC_USIGN (etype1)
              /* if this operand is promoted to a larger type,
                 then it will be promoted to a signed type */
              && !(bitsForType (etype1) < bitsForType (reType))
              /* char require special handling */
              && !IS_CHAR (etype1))
          || /* same for 2nd operand */
             (SPEC_USIGN (etype2)
              && !(bitsForType (etype2) < bitsForType (reType))
              && !IS_CHAR (etype2))
          || /* if both are 'unsigned char' and not promoted
                let the result be unsigned too */
             (   SPEC_USIGN (etype1)
              && SPEC_USIGN (etype2)
              && IS_CHAR (etype1)
              && IS_CHAR (etype2)
              && IS_CHAR (reType)))
    SPEC_USIGN (reType) = 1;
  else
    SPEC_USIGN (reType) = 0;

  return rType;
}

/*------------------------------------------------------------------*/
/* valMult - multiply constants                                     */
/*------------------------------------------------------------------*/
value *
valMult (value * lval, value * rval)
{
  value *val;

  /* create a new value */
  val = newValue ();
  val->type = val->etype = computeType (lval->etype,
                                        rval->etype,
                                        '*');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  /* signed and unsigned mul are the same, as long as the precision of the
     result isn't bigger than the precision of the operands. */
  if (SPEC_LONG (val->type))
    SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) *
                                    (TYPE_TARGET_ULONG) ulFromVal (rval);
  else if (SPEC_USIGN (val->type)) /* unsigned int */
    {
      TYPE_TARGET_ULONG ul = (TYPE_TARGET_UINT) ulFromVal (lval) *
                             (TYPE_TARGET_UINT) ulFromVal (rval);

      SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ul;
      if (ul != (TYPE_TARGET_UINT) ul)
        //werror (W_INT_OVL);
		printf("Error: Result is overload");
    }
  else /* signed int */
    {
      TYPE_TARGET_LONG l = (TYPE_TARGET_INT) floatFromVal (lval) *
                           (TYPE_TARGET_INT) floatFromVal (rval);

      SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) l;
      if (l != (TYPE_TARGET_INT) l)
        //werror (W_INT_OVL);
		printf("Error: Result is overload");
    }
  return cheapestVal (val);
}

/*------------------------------------------------------------------*/
/* valDiv  - Divide   constants                                     */
/*------------------------------------------------------------------*/
value *
valDiv (value * lval, value * rval)
{
  value *val;

  if (floatFromVal (rval) == 0)
    {
      //werror (E_DIVIDE_BY_ZERO);
		printf("Error: E_DIVIDE_BY_ZERO");
      return rval;
    }

  /* create a new value */
  val = newValue ();
  val->type = val->etype = computeType (lval->etype,
                                        rval->etype,
                                        '/');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) /
          (TYPE_TARGET_ULONG) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) /
          (TYPE_TARGET_LONG) ulFromVal (rval);
    }
  else
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) /
          (TYPE_TARGET_UINT) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) /
          (TYPE_TARGET_INT) ulFromVal (rval);
    }
  return cheapestVal (val);
}

/*------------------------------------------------------------------*/
/* valMod  - Modulus  constants                                     */
/*------------------------------------------------------------------*/
value *
valMod (value * lval, value * rval)
{
  value *val;

  /* create a new value */
  val = newValue();
  val->type = val->etype = computeType (lval->etype,
                                        rval->etype,
                                        '%');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) %
          (TYPE_TARGET_ULONG) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) %
          (TYPE_TARGET_LONG) ulFromVal (rval);
    }
  else
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) %
          (TYPE_TARGET_UINT) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) %
          (TYPE_TARGET_INT) ulFromVal (rval);
    }
  return cheapestVal (val);
}


/*------------------------------------------------------------------*/
/* valPlus - Addition constants                                     */
/*------------------------------------------------------------------*/
value *
valPlus (value * lval, value * rval)
{
  value *val;

  /* create a new value */
  val = newValue();
  val->type = val->etype = computeType (lval->etype,
                                        rval->etype,
                                        '+');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) +
         (TYPE_TARGET_ULONG) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) +
          (TYPE_TARGET_LONG) ulFromVal (rval);
    }
  else
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) +
          (TYPE_TARGET_UINT) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) +
          (TYPE_TARGET_INT) ulFromVal (rval);
    }
  return cheapestVal (val);
}

/*------------------------------------------------------------------*/
/* valMinus - Addition constants                                    */
/*------------------------------------------------------------------*/
value *
valMinus (value * lval, value * rval)
{
  value *val;

  /* create a new value */
  val = newValue();
  val->type = val->etype = computeType (lval->etype,
                                        rval->etype,
                                        '-');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) -
          (TYPE_TARGET_ULONG) ulFromVal (rval);
      else
        SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) -
          (TYPE_TARGET_LONG) ulFromVal (rval);
    }
  else
   {
     if (SPEC_USIGN (val->type))
       SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) -
         (TYPE_TARGET_UINT) ulFromVal (rval);
     else
       SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) -
         (TYPE_TARGET_INT) ulFromVal (rval);
    }
  return cheapestVal (val);
}

/*------------------------------------------------------------------*/
/* valShift - Shift left or right                                   */
/*------------------------------------------------------------------*/
value *
valShift (value * lval, value * rval, int lr)
{
  value *val;

  /* create a new value */
  val = newValue();
  val->type = val->etype = computeType (lval->etype,
                                        NULL,
                                        'S');
  SPEC_SCLS (val->etype) = S_LITERAL; /* will remain literal */

  if (getSize (val->type) * 8 <= (TYPE_TARGET_ULONG) ulFromVal (rval) &&
       /* left shift */
      (lr ||
        /* right shift and unsigned */
       (!lr && SPEC_USIGN (rval->type))))
    {
      //werror (W_SHIFT_CHANGED, (lr ? "left" : "right"));
		printf("shift changed to zero");
    }

  if (SPEC_LONG (val->type))
    {
      if (SPEC_USIGN (val->type))
        {
          SPEC_CVAL (val->type).v_ulong = lr ?
            (TYPE_TARGET_ULONG) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) : \
            (TYPE_TARGET_ULONG) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
        }
      else
        {
          SPEC_CVAL (val->type).v_long = lr ?
            (TYPE_TARGET_LONG) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) : \
            (TYPE_TARGET_LONG) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
        }
    }
  else
    {
      if (SPEC_USIGN (val->type))
        {
          SPEC_CVAL (val->type).v_uint = lr ?
            (TYPE_TARGET_UINT) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) : \
            (TYPE_TARGET_UINT) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
        }
      else
        {
          SPEC_CVAL (val->type).v_int = lr ?
            (TYPE_TARGET_INT) ulFromVal (lval) << (TYPE_TARGET_ULONG) ulFromVal (rval) : \
            (TYPE_TARGET_INT) ulFromVal (lval) >> (TYPE_TARGET_ULONG) ulFromVal (rval);
        }
    }
  return cheapestVal (val);
}

/*------------------------------------------------------------------*/
/* valBitwise - Bitwise operation                                   */
/*------------------------------------------------------------------*/
value *
valBitwise (value * lval, value * rval, int op)
{
  value *val;

  /* create a new value */
  val = newValue ();
  val->type = computeType (lval->etype, rval->etype, op);
  val->etype = getSpec (val->type);
  SPEC_SCLS (val->etype) = S_LITERAL;

  switch (op)
    {
    case '&':
      if (SPEC_LONG (val->type))
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) &
              (TYPE_TARGET_ULONG) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) &
              (TYPE_TARGET_LONG) ulFromVal (rval);
        }
      else
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) &
              (TYPE_TARGET_UINT) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_int = (TYPE_TARGET_INT) ulFromVal (lval) &
              (TYPE_TARGET_INT) ulFromVal (rval);
        }
      break;

    case '|':
      if (SPEC_LONG (val->type))
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) |
              (TYPE_TARGET_ULONG) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) |
              (TYPE_TARGET_LONG) ulFromVal (rval);
        }
      else
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) |
              (TYPE_TARGET_UINT) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_int =
              (TYPE_TARGET_INT) ulFromVal (lval) | (TYPE_TARGET_INT) ulFromVal (rval);
        }

      break;

    case '^':
      if (SPEC_LONG (val->type))
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_ulong = (TYPE_TARGET_ULONG) ulFromVal (lval) ^
              (TYPE_TARGET_ULONG) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_long = (TYPE_TARGET_LONG) ulFromVal (lval) ^
              (TYPE_TARGET_LONG) ulFromVal (rval);
        }
      else
        {
          if (SPEC_USIGN (val->type))
            SPEC_CVAL (val->type).v_uint = (TYPE_TARGET_UINT) ulFromVal (lval) ^
              (TYPE_TARGET_UINT) ulFromVal (rval);
          else
            SPEC_CVAL (val->type).v_int =
              (TYPE_TARGET_INT) ulFromVal (lval) ^ (TYPE_TARGET_INT) ulFromVal (rval);
        }
      break;
    }

  return cheapestVal(val);
}

/*------------------------------------------------------------------*/
/* valAndOr   - Generates code for and / or operation               */
/*------------------------------------------------------------------*/
value *
valLogicAndOr (value * lval, value * rval, int op)
{
  value *val;

  /* create a new value */
  val = newValue ();
  val->type = val->etype = newCharLink ();
  val->type->_class = SPECIFIER;
  SPEC_SCLS (val->type) = S_LITERAL;    /* will remain literal */
  SPEC_USIGN (val->type) = 1;

  switch (op)
    {
    case AND_OP:
      SPEC_CVAL (val->type).v_int = floatFromVal (lval) && floatFromVal (rval);
      break;

    case OR_OP:
      SPEC_CVAL (val->type).v_int = floatFromVal (lval) || floatFromVal (rval);
      break;
    }


  return val;
}

/*------------------------------------------------------------------*/
/* valCastLiteral - casts a literal value to another type           */
/*------------------------------------------------------------------*/
value *
valCastLiteral (sym_link * dtype, double fval)
{
  value *val;
  unsigned long l = double2ul (fval);

  if (!dtype)
    return NULL;

  val = newValue ();
  if (dtype)
    val->etype = getSpec (val->type = copyLinkChain (dtype));
  else
    {
      val->etype = val->type = newLink (SPECIFIER);
      SPEC_NOUN (val->etype) = V_VOID;
    }
  SPEC_SCLS (val->etype) = S_LITERAL;

  /* if it is not a specifier then we can assume that */
  /* it will be an unsigned long                      */
  if (!IS_SPEC (val->type))
    {
      SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) l;
      return val;
    }

  switch (SPEC_NOUN (val->etype))
    {
    case V_CHAR:
      if (SPEC_USIGN (val->etype))
        SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UCHAR) l;
      else
        SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_CHAR) l;
      break;

    default:
      if (SPEC_LONG (val->etype))
        {
          if (SPEC_USIGN (val->etype))
            SPEC_CVAL (val->etype).v_ulong = (TYPE_TARGET_ULONG) l;
          else
            SPEC_CVAL (val->etype).v_long = (TYPE_TARGET_LONG) l;
        }
      else
        {
          if (SPEC_USIGN (val->etype))
            SPEC_CVAL (val->etype).v_uint = (TYPE_TARGET_UINT) l;
          else
            SPEC_CVAL (val->etype).v_int = (TYPE_TARGET_INT) l;
        }
    }

  return val;
}

/*------------------------------------------------------------------*/
/* symbolVal - creates a value for a symbol                         */
/*------------------------------------------------------------------*/
value *
symbolVal (symbol * sym)
{
  value *val;

  if (!sym)
    return NULL;

  val = newValue ();
  val->sym = sym;

  if (sym->type)
    {
      val->type = sym->type;
      val->etype = getSpec (val->type);
    }

  if (*sym->rname)
    {
        sprintf (val->name, "%s", sym->rname);
    }
  else
    {
        sprintf (val->name, "_%s", sym->name);
    }

  return val;
}

/*------------------------------------------------------------------*/
/* reverseVal - reverses the values for a value  chain        */
/*------------------------------------------------------------------*/
value *
reverseVal (value * val)
{
  value *prev, *curr, *next;

  if (!val)
    return NULL;

  prev = val;
  curr = val->next;

  while (curr)
    {
      next = curr->next;
      curr->next = prev;
      prev = curr;
      curr = next;
    }
  val->next = (void *) NULL;
  return prev;
}
